package jvm;
/*
JMM java内存模型的可见性的验证
 */
class ChangNum {
    //线程之间的通知机制，volatile能够保证内存可见性，
    /*
    一、原子性是指的是什么意思？
        不可分割，完整性，即某个线程正在做某个业务时，中间不可以被加塞或者被分割。
        需要整体完整，要么同时成功，要么同时失败。保证数据的完整性和一致性。


    二、volatile关键字的作用
    1、保证内存可见性：可见性是指线程之间的可见性，一个线程修改的状态对另一个线程是可见的。
    2、禁止指令重排：指令重排序是JVM为了优化指令、提高程序运行效率。
    3、不保证原子性

    三、volatile为什么不能保证原子性？
        出现了丢失写值的情况。
     */
    volatile int number = 10;

    public void addTo12306() {
        this.number = 12306;
    }
    //此时number前面是加了volatile关键字修饰的，volatile不保证原子性
    public /*synchronized*/ void adPlusPlus() {
        number++;
    }
}
public class Test04 {
    public static void main(String[] args) {
        ChangNum changNum = new ChangNum();

        for(int i = 1; i <=20; i++) {
            new Thread(() -> {
            //线程执行方法语句
                for (int j = 1; j <= 1000 ; j++) {
                    changNum.adPlusPlus();
                }
            },String.valueOf(i)).start();
          }
        //需要等待上面20个线程全部完成后，再用main线程去读取最终的结果。
        //判断上述线程是否都执行完毕了
        while (Thread.activeCount() > 2) {
            //礼让线程，让出cpu
            Thread.yield();
        }

        System.out.println(Thread.currentThread().getName() + "\t finally number value :" + changNum.number);
    }
    //volatile可以保证可见性，及时通知其他线程，主物理内存的值已经修改。
    public static void seeOKByVolatile() {
        ChangNum changNum = new ChangNum();

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "  **************Come in******");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            changNum.addTo12306();
            System.out.println(Thread.currentThread().getName() + " number value : " + changNum.number);
        },"AAAAA").start();

        while (changNum.number == 10) {

        }

        System.out.println(Thread.currentThread().getName() + "\t number value :" + changNum.number);
    }
}
